﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LockCrypt.Core;

namespace LockCrypt.DAL {
    /// <summary>
    /// Configuration manager for LockCrypt data layer
    /// </summary>
    public static class DalConfigurationManager {
        private static IDbProvider _provider;
        /// <summary>
        /// Gets or sets the database provider.
        /// </summary>
        /// <value>The database provider.</value>
        public static IDbProvider Provider { 
            get {
                if(_provider == null) {
                    _provider = new NullDbProvider();
                }
                return _provider;
            }
            set { _provider = value; }
        }

        /// <summary>
        /// Gets the current encryption key.
        /// </summary>
        /// <value>The current encryption key.</value>
        public static string EncryptionKey {
            get { return Provider == null || Provider.Encryption == null ? null : Provider.Encryption.EncryptionKey; }
            set {
                if(Provider != null) {
                    Provider.Encryption.EncryptionKey = value;
                }
            }
        }
            /// <summary>
        /// Gets the current encryption algorithm.
        /// </summary>
        /// <value>The current encryption algorithm.</value>
        public static EncryptionProviders EncryptionAlgorithm {
            get { return Provider == null || Provider.Encryption == null ? EncryptionProviders.None : Provider.Encryption.EncryptionAlgorithm; }
        }

        /// <summary>
        /// Configures the data layer with a specified configuration.
        /// </summary>
        /// <param name="configuration">The configuration.</param>
        public static void Configure(IDalConfiguration configuration) {
            Provider = configuration.Provider;
        }

        /// <summary>
        /// Determines whether the selected provider type uses a file as a backing store.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if the selected provider type uses a file as a backing store, otherwise <c>false</c>.
        /// </value>
        public static bool IsProviderFileBased(Constants.DatabaseType providerType) {
            return providerType == Constants.DatabaseType.Legacy || providerType == Constants.DatabaseType.SQLite || providerType == Constants.DatabaseType.XML;
        }

        /// <summary>
        /// Gets a database provider.
        /// </summary>
        /// <param name="databaseType">Type of the database.</param>
        /// <param name="encryptionAlgorithm">The encryption algorithm.</param>
        /// <param name="encryptionPassword">The password (can be <c>null</c>).</param>
        /// <param name="connectionString">The connection string.</param>
        /// <returns>
        /// A provider which can access the specified database.
        /// </returns>
        public static IDbProvider GetProvider(Constants.DatabaseType databaseType, EncryptionProviders encryptionAlgorithm, string encryptionPassword, string connectionString) {
            IEncryptionService encryptionService = CoreConfigurationManager.GetEncryptionProvider(encryptionAlgorithm, encryptionPassword);
            encryptionService.EncryptionKey = encryptionPassword;
            IDbProvider provider;
            try {
                switch(databaseType) {
                    case Constants.DatabaseType.SQLite:
                        provider = new SQLiteProvider(connectionString, encryptionService);
                        break;
                    case Constants.DatabaseType.Legacy:
                        provider = new LegacyProvider(connectionString);
                        break;
                    case Constants.DatabaseType.MySQL:
                        provider = new MySQLProvider(connectionString, encryptionService);
                        break;
                    case Constants.DatabaseType.XML:
                    default:
                        provider = new XmlProvider(connectionString, encryptionService);
                        break;
                }
            } catch {
                provider = new XmlProvider(connectionString, encryptionService);
            }
            return provider;
        }

        /// <summary>
        /// Gets a database provider.
        /// </summary>
        /// <param name="databaseType">Type of the database.</param>
        /// <param name="encryptionAlgorithm">The encryption algorithm.</param>
        /// <param name="encryptionPassword">The password (can be <c>null</c>).</param>
        /// <param name="credentials">The credentials used to connect.</param>
        /// <returns>
        /// A provider which can access the specified database.
        /// </returns>
        public static IDbProvider GetProvider(Constants.DatabaseType databaseType, EncryptionProviders encryptionAlgorithm, string encryptionPassword, NetworkDbCredentials credentials) {
            IEncryptionService encryptionService = CoreConfigurationManager.GetEncryptionProvider(encryptionAlgorithm, encryptionPassword);
            encryptionService.EncryptionKey = encryptionPassword;
            IDbProvider provider;
            try {
                switch(databaseType) {
                    case Constants.DatabaseType.MySQL:
                    default:
                        provider = new MySQLProvider(credentials, encryptionService);
                        break;
                }
            } catch {
                provider = new MySQLProvider(credentials, encryptionService);
            }
            return provider;
        }
    }

    /// <summary>
    /// Contains database configuration data.
    /// </summary>
    public interface IDalConfiguration {
        /// <summary>
        /// Gets or sets the database provider.
        /// </summary>
        /// <value>The database provider.</value>
        IDbProvider Provider { get; set; }
    }
}
